1use crate::re::BSIntrusiveRefCounted::BSIntrusiveRefCountedTrait;
6use crate::re::TESBox::TESBox;
7use core::fmt::{self, Debug};
8use core::marker::PhantomData;
9use core::ops::{Deref, DerefMut};
10use core::ptr::{self, NonNull};
11use stdx::ptr::Unique;
12
13pub trait ManageBSTSmartPointer {
15 #[inline]
17 fn acquire<T>(_ptr: *mut T)
18 where
19 T: BSIntrusiveRefCountedTrait,
20 {
21 }
22
23 #[inline]
29 unsafe fn release<T>(ptr: *mut T)
30 where
31 T: BSIntrusiveRefCountedTrait,
32 {
33 if !ptr.is_null() {
34 drop(unsafe { TESBox::from_raw(ptr) });
35 }
36 }
37}
38
39#[derive(Debug)]
41pub struct BSTSmartPointerIntrusiveRefCount;
42
43impl ManageBSTSmartPointer for BSTSmartPointerIntrusiveRefCount {
44 #[inline]
45 #[allow(clippy::not_unsafe_ptr_arg_deref)]
46 fn acquire<T>(ptr: *mut T)
47 where
48 T: BSIntrusiveRefCountedTrait,
49 {
50 if !ptr.is_null() {
51 (unsafe { &*ptr }).inc_ref();
52 }
53 }
54
55 #[inline]
56 unsafe fn release<T>(ptr: *mut T)
57 where
58 T: BSIntrusiveRefCountedTrait,
59 {
60 if !ptr.is_null() && (unsafe { &*ptr }).dec_ref() == 0 {
61 drop(unsafe { TESBox::from_raw(ptr) });
62 }
63 }
64}
65
66#[derive(Debug)]
68pub struct BSTSmartPointerAutoPtr;
69impl ManageBSTSmartPointer for BSTSmartPointerAutoPtr {}
70
71pub type BSTAutoPointer<T> = BSTSmartPointer<T, BSTSmartPointerAutoPtr>;
72
73#[repr(C)]
82pub struct BSTSmartPointer<T, M = BSTSmartPointerIntrusiveRefCount>
83where
84 T: BSIntrusiveRefCountedTrait,
85 M: ManageBSTSmartPointer,
86{
87 ptr: Option<Unique<T>>,
89 _marker: PhantomData<M>,
90}
91
92impl<T, M> BSTSmartPointer<T, M>
93where
94 T: BSIntrusiveRefCountedTrait,
95 M: ManageBSTSmartPointer,
96{
97 #[inline]
101 pub unsafe fn new(ptr: *mut T) -> Self {
102 M::acquire(ptr);
103 Self { ptr: Unique::new(ptr), _marker: PhantomData }
104 }
105
106 #[inline]
108 pub fn from_non_null(ptr: NonNull<T>) -> Self {
109 M::acquire(ptr.as_ptr());
110 Self { ptr: Some(Unique::from(ptr)), _marker: PhantomData }
111 }
112
113 #[inline]
117 pub fn reset(&mut self) {
118 unsafe {
119 M::release(self.as_ptr());
120 self.ptr = None; }
122 }
123
124 #[inline]
126 pub fn from_box(value: TESBox<T>) -> Self {
127 let ptr = TESBox::into_raw(value);
128 unsafe { Self::new(ptr) }
130 }
131
132 #[inline]
136 pub const fn as_ref(&self) -> Option<&T> {
137 match &self.ptr {
138 Some(p) => unsafe { Some(p.as_ref()) },
139 None => None,
140 }
141 }
142
143 #[inline]
145 pub const fn as_mut(&mut self) -> Option<&mut T> {
146 match &mut self.ptr {
147 Some(p) => unsafe { Some(p.as_mut()) },
148 None => None,
149 }
150 }
151
152 #[inline]
154 pub const fn as_ptr(&self) -> *mut T {
155 match self.ptr {
156 Some(p) => p.as_ptr(),
157 None => ptr::null_mut(),
158 }
159 }
160
161 #[inline]
163 pub const fn is_null(&self) -> bool {
164 self.ptr.is_none()
165 }
166}
167
168impl<T, M> fmt::Debug for BSTSmartPointer<T, M>
169where
170 T: BSIntrusiveRefCountedTrait + fmt::Debug,
171 M: ManageBSTSmartPointer,
172{
173 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 let mut s = f.debug_struct("BSTSmartPointer");
175 match self.as_ref() {
176 Some(value) => s.field("ptr", value),
177 None => s.field("ptr", &"null"),
178 };
179 s.finish()
180 }
181}
182
183impl<T, M> Default for BSTSmartPointer<T, M>
184where
185 T: BSIntrusiveRefCountedTrait,
186 M: ManageBSTSmartPointer,
187{
188 #[inline]
189 fn default() -> Self {
190 Self { ptr: None, _marker: PhantomData }
191 }
192}
193
194impl<T, M> Drop for BSTSmartPointer<T, M>
195where
196 T: BSIntrusiveRefCountedTrait,
197 M: ManageBSTSmartPointer,
198{
199 #[inline]
200 fn drop(&mut self) {
201 self.reset();
202 }
203}
204
205impl<T, M> Deref for BSTSmartPointer<T, M>
206where
207 T: BSIntrusiveRefCountedTrait,
208 M: ManageBSTSmartPointer,
209{
210 type Target = T;
211
212 #[inline]
218 fn deref(&self) -> &Self::Target {
219 self.as_ref().expect("Dereferencing null pointer")
220 }
221}
222
223impl<T, M> DerefMut for BSTSmartPointer<T, M>
224where
225 T: BSIntrusiveRefCountedTrait,
226 M: ManageBSTSmartPointer,
227{
228 #[inline]
234 fn deref_mut(&mut self) -> &mut Self::Target {
235 self.as_mut().expect("Dereferencing null pointer")
236 }
237}
238
239impl<T, M> Clone for BSTSmartPointer<T, M>
240where
241 T: BSIntrusiveRefCountedTrait,
242 M: ManageBSTSmartPointer,
243{
244 #[inline]
245 fn clone(&self) -> Self {
246 M::acquire(self.as_ptr());
247 Self { ptr: self.ptr, _marker: PhantomData }
248 }
249}
250
251impl<T, M> PartialEq for BSTSmartPointer<T, M>
252where
253 T: BSIntrusiveRefCountedTrait,
254 M: ManageBSTSmartPointer,
255{
256 #[inline]
257 fn eq(&self, other: &Self) -> bool {
258 match (self.ptr, other.ptr) {
259 (Some(p1), Some(p2)) => p1.as_non_null_ptr() == p2.as_non_null_ptr(),
260 (None, None) => true,
261 _ => false,
262 }
263 }
264}
265
266impl<T, M> Eq for BSTSmartPointer<T, M>
267where
268 T: BSIntrusiveRefCountedTrait,
269 M: ManageBSTSmartPointer,
270{
271}
272
273impl<T, M> PartialEq<*mut T> for BSTSmartPointer<T, M>
274where
275 T: BSIntrusiveRefCountedTrait,
276 M: ManageBSTSmartPointer,
277{
278 #[inline]
279 fn eq(&self, other: &*mut T) -> bool {
280 self.as_ptr() == *other
281 }
282}
283
284impl<T, M> PartialEq<Option<*mut T>> for BSTSmartPointer<T, M>
285where
286 T: BSIntrusiveRefCountedTrait,
287 M: ManageBSTSmartPointer,
288{
289 #[inline]
290 fn eq(&self, other: &Option<*mut T>) -> bool {
291 Some(self.as_ptr()) == *other
292 }
293}
294
295impl<T, M> PartialEq<ptr::NonNull<T>> for BSTSmartPointer<T, M>
296where
297 T: BSIntrusiveRefCountedTrait,
298 M: ManageBSTSmartPointer,
299{
300 #[inline]
301 fn eq(&self, other: &ptr::NonNull<T>) -> bool {
302 self.as_ptr() == other.as_ptr()
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use super::*;
309 use core::sync::atomic::{AtomicU32, Ordering};
310
311 #[repr(C)]
312 #[derive(Debug)]
313 struct TestObject {
314 ref_count: AtomicU32,
315 value: i32,
316 }
317
318 impl TestObject {
319 const fn new(value: i32) -> Self {
320 Self { ref_count: AtomicU32::new(0), value }
321 }
322 }
323
324 impl BSIntrusiveRefCountedTrait for TestObject {
325 fn inc_ref(&self) -> u32 {
326 self.ref_count.fetch_add(1, Ordering::AcqRel) + 1
327 }
328
329 fn dec_ref(&self) -> u32 {
330 self.ref_count.fetch_sub(1, Ordering::AcqRel) - 1
331 }
332 }
333 #[test]
336 fn test_smart_pointer() {
337 {
338 let obj = TESBox::new(TestObject::new(42));
339 let mut ptr = BSTSmartPointer::<TestObject>::from_box(obj);
340 assert_eq!(ptr.value, 42);
341 assert!(ptr.as_ref().is_some());
342 assert_eq!(ptr.as_ref().map(|p| p.ref_count.load(Ordering::Acquire)), Some(1));
343
344 let mut ptr2 = ptr.clone();
346 assert_eq!(ptr2.value, 42);
347 assert_eq!(ptr.as_ref().map(|p| p.ref_count.load(Ordering::Acquire)), Some(2));
348
349 ptr.reset();
350 assert_eq!(ptr2.as_ref().map(|p| p.ref_count.load(Ordering::Acquire)), Some(1));
351
352 assert!(ptr.as_ref().is_none());
353 assert!(ptr2.as_ref().is_some());
354 ptr2.reset();
355 }
356 }
357
358 #[test]
359 fn test_auto_pointer() {
360 let obj = TESBox::new(TestObject::new(123));
361 let mut auto_ptr = BSTAutoPointer::from_box(obj);
362 assert_eq!(auto_ptr.value, 123);
363
364 auto_ptr.reset();
365 assert!(auto_ptr.as_ref().is_none());
366 }
367}